// #ifndef __tenacitas_communication__locator__h__
// #define __tenacitas_communication__locator__h__


// // =============================================================================
// /** @file
//     This file defines the @p locator class
// */

// // =============================================================================
// //                                 C++ Headers
// #include <cstdint>
// #include <thread>

// // =============================================================================
// //                                 3rds Headers

// // =============================================================================
// //                                 Our Headers
// #include "processor.h"

// // =============================================================================
// //                                 Namespaces
// using namespace std;

// // =============================================================================
// //                                 Macro Constants

// // =============================================================================
// //                                 Macro Communications

// /** namespace of the organization */
// namespace tenacitas {
//     /** A library which provides classes that help writing software that have to
//         receive and handle communications

//         This library is based on the books: "Internetworking with TCP/IP",
//         volume 3, by Douglas E. Comer and David L. Stevens, published by
//         Prentice Hall; and "Unix Network Programming", by Richard Stevens,
//         published by Prentice Hall */   
//     namespace communication {

//         // =========================== Typedefs ===========================

//         // ============================ Pre-Declarations ==================

//         // ============================ Attributes ========================
//         /** */

//         // ============================ Functions =========================
//         /** */

//         // ============================ Classes ===========================

//         /** Receives communications, possibly composed by many messages, through some
//             type of connection, translates the messages in some type of specific
//             data, and passes them to some type of application, using some type of
//             concurrence stratergy  

            
//             ###################################################################
//             @tparam t_message_factory defines the type of message, and the type
//             of message pointer.

//             It must implement:

//             <code>
//             message, the type of the message that compounds a communication

//             message_ptr, the type of pointer to @p message 
//             <endcode>

//             ###################################################################
//             @p t_connector_factory creates objects that puts the locator ready
//             to accept connections, and actually accepts connections

//             must implement:

//             <code>
//             connector, which puts the locator ready to accept connections, and
//             actually accepts connections 

//             connector_ptr, type of pointer to the @p connector

//             connection, through where messages will arrive, and through where
//             they will be sent

//             connection_ptr, type of pointer to the @p connection
            
//             static connector_ptr create( ), which created a @p connector pointer
//             <endcode>

//             ###################################################################
//             @p connector puts the locator ready to accept connections, and
//             actually accepts connections.

//             It must implement:
//             <code>

//             bool start( ), which makes the connector ready to accept connections
            
//             connection_ptr connected( ), which creates a connection to the
//             (transmitting) software that will send and receive messages

//             <endcode>

//             ###################################################################
//             @tparam t_concurrence_factory crates objects that are responsible for
//             controlling the concurrence of message handling.
            
//             It must implement:
//             <code>
//             concurrence, which is the type of concurrence used

//             concurrence_ptr, type of pointer to the @p concurrence

//             static concurrence_ptr create( ), which creates a @p concurrence
//             pointer 
//             <endcode>

//             ###################################################################
//             @p concurrence must implement:

//             <code>
//             void operator( )( tenacitas_communication::
//             processor<t_message_factory,
//             t_connector_factory,
//             t_message_io_factory,
//             t_translator_factory,
//             t_application_factory> & p_processor),
//             which will start transmitting messages by calling
//             <tt>processor( )</tt> 
//             <endcode>

//             ###################################################################
//             @p t_message_io_factory is responsible for creating objects that will
//             read messages from a @p t_connector_factory::connection, and write
//             messages through a @p t_connector_factory::connection  

//             It must implement:
//             <code>
//             message_io

//             message_io_ptr

//             static message_io_ptr create( )
//             <endcode>

//             ###################################################################
//             @p message_io is responsible for reading messages from a @p
//             connection, and writing messages through a @p
//             t_connector_factory::connection. 

//             It must implement:
//             <code>
//             t_message_factory::message_ptr
//             read( t_connector_factory::connection_ptr p_con ), which reads a
//             message from a @p t_connector_factory::connection  

//             void write( t_connector_factory::connection_ptr p_con,
//             t_message_factory::message_ptr p_message ), which writes
//             a message through a @p t_connector_factory::connection   


//             ###################################################################
//             @tparam t_translator_factory creates objects that will translate a @p
//             t_message_factory::message into an app_data to suitable for the @p
//             t_application_factory::application

//             It must implement:
//             <code>
//             translator

//             translator_ptr

//             app_data
            
//             app_data_ptr

//             static translator_ptr create( )
//             <endcode>
            
//             ###################################################################
//             @p translator translate a @p t_message_factory::message object into
//             into an app_data to suitable for the @p
//             t_application_factory::application 

//             It must implement:
//             <code>

//             t_translator_factory::app_data_ptr to_app_data
//             ( const t_message_factory::message_ptr p_message );

//             t_message_factory::message_ptr p_message to_message
//             ( const t_translator_factory::app_data_ptr );

//             <endcode>
            
            
//             ###################################################################
//             @tparam t_application_factory creates objects that handle the
//             message read by a @p connection object.

//             It must implement:
//             <code>
//             application

//             application_ptr

//             static application_ptr create( )
//             <endcode>

//             ###################################################################
//             @p application is responsible for handling translated messages.

//             It must implement:

//             <code>

//             void operator( )( t_translator_factory::app_data_ptr p_app_data,
//             t_connector_factory::connection_ptr p_con,
//             t_message_io_factory::message_io_ptr p_message_io );

//             <endcode>

//             @todo: define timeout for waiting output connection
//             @todo: where to define timeout for reading message: in @p
//             t_connector_factory::connection, or in the @p locator?

// 	    ###################################################################
//             @tparam t_timeout_factory creates @ptimeout objects that determine
//             how long a @p t_application_factory::application must wait for a new
//             @p t_message_factory::message. 

// 	    It must implement:
// 	    <code>
// 	    timeout, which defines for how long a @p
// 	    t_application_factory::application must wait for a new @p
// 	    t_message_factory::message. 

// 	    timeout_ptr, a reference to a @p timeout object

// 	    timeout_ptr static create( ), which creates references to @p timeout

// 	    ###################################################################
// 	    @p timeout defines for how long a @p
// 	    t_application_factory::application must wait for a new @p
// 	    t_message_factory::message. 

// 	    It must implement:

// 	    @todo define @p timeout interface
            
//             @nosubgrouping 
//         */

//         template <
//             typename t_message_types,
//             typename t_connection_types,
//             typename t_app_data_types,
//             typename t_translator_types,
//             typename t_concurrence_types,
//             typename t_application_types,
//             typename t_connector_types,
//             typename t_timeout_types,
//             typename t_message_io_types,
//             typename t_log_types
//             >
//         class locator {

//         public:

//             // --- locator - Public Internal Types ------------------------

//             typedef t_message_types message_types;
//             typedef typename message_types::message message;
//             typedef typename message_types::message_ptr message_ptr;

//             typedef t_app_data_types app_data_types;
//             typedef typename app_data_types::app_data app_data;
//             typedef typename app_data_types::app_data_ptr app_data_ptr;

//             typedef t_connection_types connection_types;
//             typedef typename connection_types::connection connection;
//             typedef typename connection_types::connection_ptr connection_ptr;

//             typedef t_translator_types translator_types;
//             typedef typename translator_types::translator_factory translator_factory;
//             typedef typename translator_types::translator_factory_ptr
//             translator_factory_ptr; 
//             typedef typename translator_types::translator translator;
//             typedef typename translator_types::translator_ptr translator_ptr;

//             typedef t_concurrence_types concurrence_types;
//             typedef typename concurrence_types::concurrence_factory concurrence_factory;
//             typedef typename concurrence_types::concurrence_factory_ptr
//             concurrence_factory_ptr; 
//             typedef typename concurrence_types::concurrence concurrence;
//             typedef typename concurrence_types::concurrence_ptr concurrence_ptr;

//             typedef t_application_types application_types;
//             typedef typename application_types::application_factory application_factory;
//             typedef typename application_types::application_factory_ptr
//             application_factory_ptr; 
//             typedef typename application_types::application application;
//             typedef typename application_types::application_ptr application_ptr;

//             typedef t_connector_types connector_types;
//             typedef typename connector_types::connector_factory connector_factory;
//             typedef typename connector_types::connector_factory_ptr
//             connector_factory_ptr; 
//             typedef typename connector_types::connector connector;
//             typedef typename connector_types::connector_ptr connector_ptr;

//             typedef t_timeout_types timeout_types;
//             typedef typename timeout_types::timeout_factory timeout_factory;
//             typedef typename timeout_types::timeout_factory_ptr
//             timeout_factory_ptr; 
//             typedef typename timeout_types::timeout timeout;
//             typedef typename timeout_types::timeout_ptr timeout_ptr;

//             typedef t_message_io_types message_io_types;
//             typedef typename message_io_types::message_io_factory message_io_factory;
//             typedef typename message_io_types::message_io_factory_ptr
//             message_io_factory_ptr; 
//             typedef typename message_io_types::message_io message_io;
//             typedef typename message_io_types::message_io_ptr message_io_ptr;


//             typedef communication::processor<message_types,
//                                        connection_types,
//                                        app_data_types,
//                                        translator_types,
//                                        application_types,
//                                        timeout_types,
//                                        message_io_types> processor;

//             // --- locator - Public Constructors --------------------------

//             /** Constructor

//                 A @p locator is created unable to receive messages.
//                 One must call @p start_sync or @p start_async so that @p locator
//                 starts receiving messages 
//             */
//             locator( translator_factory_ptr p_translator_factory,
//                       concurrence_factory_ptr p_concurrence_factory,
//                       application_factory_ptr p_application_factory, 
//                       connector_factory_ptr p_connector_factory,
//                       timeout_factory_ptr p_timeout_factory,
//                       message_io_factory_ptr p_message_io_factory )
//                 : m_stop( true ),
//                   m_start_th( ),
//                   m_translator_factory( p_translator_factory ),
//                   m_concurrence_factory( p_concurrence_factory ),
//                   m_application_factory( p_application_factory ),
//                   m_connector_factory( p_connector_factory ),
//                   m_timeout_factory( p_timeout_factory ),
//                   m_message_io_factory( p_message_io_factory ) {}

//             /** Copy constructor not allowed */
//             locator( const locator & ) = delete;
                

//             /** Destructor */
//             ~locator( ) {
//                 if ( !m_stop ) {
//                     m_stop = true;
//                     if ( m_start_th != std::thread::thread( ) ) {
//                         m_start_th.join( );
//                     }
//                 }
//             }
            

//             // --- locator - Public Processors ----------------------------

//             /** Starts receiving messages asynchronously

//                 @param [in] p_connector determines the connection where the @p
//                 locator will receive messages, and the connection where messages
//                 will be sent back to
//             */
//             void start_async( ) {
//                 if ( !m_stop ) {
//                     return;
//                     // @todo: log warn that the locator was already started
//                 }
//                 m_stop = false;
                
//                 m_start_th = std::thread( locator::start, *this );
//             }

//             /** Starts receiving messages synchronously

//                 @param [in] p_connector determines the connection where the @p
//                 locator will receive messages, and the connection where messages
//                 will be sent back to
//             */
//             void start_sync( ) {
//                 if ( !m_stop ) {
//                     return;
//                     // @todo: log warn that the locator was already started
//                 }

//                 m_stop = false;
                
//                 start( );
//             }

//             /** Stops receiving messages */
//             void stop( ) {
//                 m_stop = true;
//             }

//             // --- locator - Public Operators -----------------------------

//             /** Assignment not allowed */
//             locator & operator=( const locator & ) = delete;
            
//         private:

//             // --- locator - Private Processors ---------------------------

//             /** Starts receiving message data */
//             void start( ) {

//                 // concurrence policy for transmitting messages
//                 concurrence_ptr l_concurrence = m_concurrence_factory->create( ); 

//                 // where will the messages be delivered?
//                 connector_ptr l_connector = m_connector_factory->create( );

//                 if ( !l_connector ) {
//                     // @todo log critical; throw exception
//                     std::cout << "Error creating connector" << std::endl;
//                 }

//                 // waits for connections
//                 if ( !l_connector->start( ) ) {
//                     // @todo log critical; throw exception
//                     std::cout << "Error starting connector" << std::endl;
//                 }
                

//                 // we will process messages, using the defined concurrence
//                 // policy, until someone tells us to stop
//                 while ( !m_stop ) {

//                     std::cout << "Waiting for a connection...\n";

//                     // wait until a connection to send messages to is defined,
//                     // which is done by some, possibly, remote software
//                     connection_ptr l_connection = l_connector->connected( );

//                     if ( !l_connection ) {
//                         // @todo log critical; throw exception
//                         std::cout << "Error connection established, but empty" << std::endl;
//                     }
//                     else {
//                         std::cout << "Connection established"  << std::endl;
//                     }

//                     // our message processor, a class to allow concurrent message
//                     // transmitting invocation
//                     processor l_processor( l_connection,
//                                            m_translator_factory,
//                                            m_application_factory,
//                                            m_timeout_factory,
//                                            m_message_io_factory );

//                     // starting the message transmitting, possibly asynchronously
//                     l_concurrence->submit( l_processor );
//                 }
//             }

//             // --- locator - Private Operators ----------------------------

//             // --- locator - Private Attributes ---------------------------

//             /** Flags that the @p m_start_th thread must stop */
//             bool m_stop;
            

//             /** Thread where the @p locator will start receiving messages */
//             std::thread m_start_th;

//             translator_factory_ptr m_translator_factory;
//             concurrence_factory_ptr m_concurrence_factory;
//             application_factory_ptr m_application_factory;
//             connector_factory_ptr m_connector_factory;
//             timeout_factory_ptr m_timeout_factory;
//             message_io_factory_ptr m_message_io_factory;
            

//         };
//     }
// }

// // =============================================================================
// //                     I M P L E M E N T A T I O N
// // =============================================================================

// using namespace tenacitas::communication;


// #endif
